#include "IAudioIn.h"

void runIn(IAudioIn *io)
{
	io->runIn();	
}


IAudioIn::IAudioIn(IBuffer2	*buf)
{
	this->_deviceList = NULL;
	this->_deviceTable = NULL;
	this->_currentDevice = NULL;
	this->_inRun = false;
	this->_freq = 44100;
	this->_sleepReactivity = 11;
	this->_buf = buf;
}

IAudioIn::~IAudioIn()
{
	if (this->_inRun == true)
		this->_inRun = false;

	delete this->_deviceList;
	delete this->_deviceTable;

	if (this->_currentDevice != NULL)
		alcCaptureCloseDevice(this->_currentDevice);
}

char **IAudioIn::detectDevice()
{
	// test if lister is avaible 
	if(alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
	{
		int numDevice = 0;
		char *ptr;

		// delete old device list if exist
		if (this->_deviceList != NULL)
		{
			delete this->_deviceList;
		}
		// get list of device
		this->_deviceList = (char*)alcGetString
		(
			NULL, 
			ALC_ALL_DEVICES_SPECIFIER
		);
		if (this->_deviceList == "")
		{
			return (char **)-1;
		}
		// count devices
		ptr = this->_deviceList;
		while( ptr && *ptr )
		{
			while (*ptr != NULL)
				++ptr;
			ptr++;
			numDevice++;
		}
		// delete old device table if exist
		if (this->_deviceTable != NULL)
		{
			delete this->_deviceTable;
		}
		// create new device table
		this->_deviceTable = new char *[numDevice];
		// complete deviceTable
		ptr = this->_deviceList;
		numDevice = 0;
		while( ptr && *ptr )
		{
			this->_deviceTable[numDevice] = ptr;
			while (*ptr != NULL)
				++ptr;
			ptr++;
			numDevice++;
		}
		this->_deviceTable[numDevice] = NULL;
	}
	else
	{
		return NULL;
	}
	return this->_deviceTable;
}

void IAudioIn::selectInDevice(char *deviceName)
{
	if (this->_currentDevice != NULL)
		alcCaptureCloseDevice(this->_currentDevice);
	this->_currentDevice = alcCaptureOpenDevice
	(
		deviceName,
		this->_freq,
		AL_FORMAT_MONO16  ,
		42000
	);
}

void IAudioIn::selectInDevice(int deviceId)
{
	if (this->_currentDevice != NULL)
		alcCaptureCloseDevice(this->_currentDevice);
	this->_currentDevice = alcCaptureOpenDevice(
		this->_deviceTable[deviceId],
		this->_freq,
		AL_FORMAT_MONO16 ,
		42000
		);
}

void IAudioIn::autoSelectInDevice()
{
	if (this->_currentDevice != NULL)
		alcCaptureCloseDevice(this->_currentDevice);
	this->_currentDevice = alcCaptureOpenDevice(
		NULL,
		this->_freq,
		AL_FORMAT_MONO16 ,
		42000
		);
}

void IAudioIn::start()
{
	// init
	if (this->_currentDevice == NULL)
		this->autoSelectInDevice();
	// start Thread
	DWORD dwThreadId;
	CreateThread
	(
		NULL,
		0,
		reinterpret_cast<LPTHREAD_START_ROUTINE>(::runIn),
		this,
		0,
		&dwThreadId
	);
}

void IAudioIn::runIn()
{
	ALCdevice						*localDevice = this->_currentDevice;
	std::vector<ALshort>			samples;
	std::vector<ALshort>::iterator	it;
	std::vector<ALshort>::iterator	end;

	this->_inRun = true;
	alcCaptureStart(localDevice);
	if (!this->_currentDevice)
		std::cout << "No Input Device" << std::endl;
	while (this->_inRun && this->_currentDevice)
	{
	
		
		ALCint samplesAvailable;

		alcGetIntegerv
		(
			localDevice, 
			ALC_CAPTURE_SAMPLES, 
			1,
			&samplesAvailable
		);


		if (samplesAvailable > 0)		
		{
		
			samples.resize(samplesAvailable);
			alcCaptureSamples
			(
				localDevice, 
				&samples[0],
				samplesAvailable
			);

			it = samples.begin();
			end = samples.end();
			while(it != end)
			{

				this->_buf->Write(&(*it), 2);

				++it;
			}
		}

		Sleep(this->_sleepReactivity);

	}
	alcCaptureStop(localDevice);
}


void IAudioIn::stop()
{
	this->_inRun = false;
}

void IAudioIn::setFrequency(unsigned int freq)
{
	this->_freq = freq;
}

void IAudioIn::setReactivity(int react)
{
	this->_sleepReactivity = react;
}